import java.util.ArrayList;

public class Adjazenzliste
{
    private ArrayList<ArrayList<Listenobjekt>> adList;

    public Adjazenzliste () {
        adList = new ArrayList<ArrayList<Listenobjekt>>();
    }

    public ArrayList getAdjazenzListe() {
        return adList;
    }

    /**
     * Sobald in der Knotenliste der Knoten k gefunden wird, wird true ausgegeben
     */
    public boolean isKnotenEnthalten (Knoten k) {
        for (ArrayList<Listenobjekt> a : adList) {
            if(a.get(0).getKnoten()==k) {
                return true;
            }
        }
        return false;
    }

    /**
     * Sobald in der Knotenliste der Knoten mit dem angegebenen Namen gefunden wird, wird true ausgegeben
     */
    public boolean isKnotenEnthalten (String name) {
        for (ArrayList<Listenobjekt> a : adList) {
            if(a!=null && a.get(0)!=null && a.get(0).getKnoten().getName()==name) {
                return true;
            }
        }
        return false;
    }

    public Knoten getKnoten (String name) {
        for (ArrayList<Listenobjekt> a : adList) {
            if(a!=null && a.get(0)!=null && a.get(0).getKnoten().getName()==name) {
                return a.get(0).getKnoten();
            }
        }
        return null;
    }

    public boolean addKnoten (Knoten k) {
        boolean erledigt=false;
        if (!isKnotenEnthalten(k)){
            ArrayList<Listenobjekt> knotenElement = new ArrayList<Listenobjekt>();
            erledigt = adList.add(knotenElement);
            if (erledigt) {
                Listenobjekt l = new Listenobjekt(k,0);
                erledigt = knotenElement.add(l);
            }
        }
        ausgabe("addKnoten ("+k.toString()+"):"); //Testzwecke
        return erledigt;
    }

    public boolean removeKnoten (String k) {
        int index = -1;
        for (ArrayList<Listenobjekt> a : adList) {
            if(a.get(0).getKnoten().getName()==k) {
                index = adList.indexOf(a);
            }
        }
        if (index >= 0) {
            if(adList.remove(index)!=null) {
                ausgabe("removeKnoten ("+k+"):"); //Testzwecke
                return true;
            }
        }
        ausgabe("removeKnoten ("+k+") hat nicht geklappt!"); //Testzwecke
        return false;
    }

    public boolean removeKnoten (Knoten k) {
        int index1 = -1, index2 = -1;
        boolean geklappt=false;
        for (ArrayList<Listenobjekt> a : adList) {
            if(a.get(0).getKnoten()==k) index1 = adList.indexOf(a);
            for(Listenobjekt kn : a) {
                if(kn.getKnoten()==k) index2 = a.indexOf(kn);
            }
            if (index2 >= 0) {
                if(a.remove(index2)!=null) geklappt = true;
                index2 = -1;
            }
        }
        if (index1 >= 0) {
            if(adList.remove(index1)!=null) geklappt = true;
        }
        ausgabe("removeKnoten ("+k.toString()+") hat geklappt: "+geklappt); //Testzwecke
        return geklappt;
    }

    public boolean isKanteEnthalten (Kante e) {
        return isKanteEnthalten (e.getStart(), e.getZiel(), e.getGewicht());
    }

    public boolean isKanteEnthalten (String startName, String zielName, String gewichtText) {
        for (ArrayList<Listenobjekt> a : adList) {
            if(a.get(0)!=null && a.get(0).getKnoten().getName()==startName) {
                for(Listenobjekt k : a) {
                    if (k.getKnoten().getName() == zielName && k.getKantenGewicht() == Double.valueOf(gewichtText)) return true;
                }
            }
        }
        return false;
    }

    public boolean isKanteEnthalten (Knoten start, Knoten ziel, double gewicht) {
        if(start != null && ziel != null) {
            for (ArrayList<Listenobjekt> a : adList) {
                if(a.get(0)!=null && a.get(0).getKnoten()==start) {
                    for(Listenobjekt k : a) {
                        if (k.getKnoten() == ziel && k.getKantenGewicht() == gewicht) return true;
                    }
                }
            }
        }
        return false;
    }

    public Kante getKante (Knoten start, Knoten ziel, double gewicht) {
        for (ArrayList<Listenobjekt> a : adList) {
            if(a.get(0).getKnoten()==start) {
                for (Listenobjekt k : a) {
                    if(k.getKnoten()==ziel && k.getKantenGewicht()==gewicht) {
                        return new Kante(start,ziel,gewicht);
                    }
                }
            }
        }
        return null;
    }

    public boolean addKante(Kante e) {
        return addKante(e.getStart(), e.getZiel(), e.getGewicht());
    }

    public boolean addKante(Knoten start, Knoten ziel, double gewicht) {
        if (!isKanteEnthalten(start, ziel, gewicht)){
            if(!isKnotenEnthalten(start)) this.addKnoten(start);
            for (ArrayList<Listenobjekt> a : adList) {
                if(a.get(0).getKnoten()==start) {
                    boolean geklappt = a.add(new Listenobjekt(ziel,gewicht));
                    ausgabe("addKante ("+start.toString()+", "+ziel.toString()+", "+gewicht+"):"); //Testzwecke
                    /*#
                     * Achtung Doppelte Kante mit unterschiedlichen Gewichten moeglich!
                     * Falls nicht gewuenscht muss die Methode isListenobjektEnthalten()
                     * implementiert werden und vor dem naechsten return daraufhin ueberprueft werden!
                     */
                    return geklappt;
                }
            }
        }
        ausgabe("addKante ("+start.toString()+", "+ziel.toString()+", "+gewicht+") hat nicht geklappt!"); //Testzwecke
        return false;
    }

    public boolean removeKante (Kante e) {
        return removeKante (e.getStart(), e.getZiel(), e.getGewicht());
    }

    public boolean removeKante (Knoten start, Knoten ziel, double gewicht) {
        if (isKanteEnthalten(start, ziel, gewicht)){
            for (ArrayList<Listenobjekt> a : adList) {
                if(a.get(0).getKnoten()==start) {
                    for (Listenobjekt k : a) {
                        if(k.getKnoten()==ziel && k.getKantenGewicht()==gewicht) {
                            boolean geklappt = a.remove(k);
                            ausgabe("removeKante ("+start.toString()+", "+ziel.toString()+", "+gewicht+"):"); //Testzwecke
                            return geklappt;
                        }
                    }
                }
            }
        }
        ausgabe("removeKante ("+start.toString()+", "+ziel.toString()+", "+gewicht+") hat nicht geklappt!"); //Testzwecke
        return false;
    }

    public boolean removeKante (String start, String ziel, double gewicht) {
        return removeKante(getKnoten(start), getKnoten(ziel), gewicht);
    }

    public boolean isEmpty() {
        return adList.isEmpty();
    }

    public void clear() {
        adList.clear();
        ausgabe(); //Testzwecke
    }

    public String toString() {
        String s="";
        s+="Adjazenzliste:\n";
        if(adList.isEmpty()) return s+="Liste ist leer!\n";
        for (ArrayList<Listenobjekt> a : adList) {
            for (Listenobjekt k : a) {
                s+=k.toString()+" --> ";
            }
            s+="null\n";
        }
        return s;
    }

    public String toString(String text) {
        return text+"\n"+toString();
    }

    public void ausgabe() {
        System.out.println(toString());
    }

    public void ausgabe(String text) {
        System.out.println(toString(text));
    }
}
